source("./utils/tianfengRwrappers.R")
Warning: The `size` argument of `element_line()` is deprecated as of ggplot2 3.4.0.
Please use the `linewidth` argument instead.
 
#获取平均表达矩阵
aver_expr_mat <- get_averexpr_mat_cluster(ctrl_filtered)
bulk_expr_mat <- read.csv("./data_tables/DEGs_from_smartSeq/nomalized_expr_tr4Tr5Tr5_2.csv",row.names = 1)
bulk_expr_mat <- bulk_expr_mat[,!(colnames(bulk_expr_mat)%in%"Tr5_2")]
colnames(aver_expr_mat) <- levels(ctrl_filtered@active.ident)
#选高差异表达
# diff_genes <- intersect(ctrl_filtered@assays[["SCT"]]@var.features, rownames(bulk_expr_mat))
diff_genes <- intersect(rownames(aver_expr_mat), rownames(bulk_expr_mat))
aver_expr_mat <- aver_expr_mat[diff_genes,]
bulk_expr_mat <- bulk_expr_mat[diff_genes,]
# normalized_counts <-  normalized_counts[diff_genes,]

cormat <- cor(aver_expr_mat,bulk_expr_mat, method = "spearman")
pheatmap(cormat, color = colorRampPalette(c("#1E90FF", "white", "#ff2121"))(400), border_color = NA, cluster_rows = T, cluster_cols = T, angle_col = 0, main = "Correlation Heatmap")

ASP bulk RNAseq

#smartseq 交叉验证 PC in scRNA-seq

degs <- read.csv("./data_tables/DEGs_from_smartSeq/up_DEGslist.csv",header = FALSE)
ctrl_markers <- read.csv("./data_tables/ctrl_markers_fig1.csv", row.names = 1)
dhm(intersect(degs$V1,rownames(ctrl_markers)), ctrl_filtered)

#ggsave(filename = paste0("highexpr_tr5",".png"), device = png, height = 8, width = 12, plot = highexprheatmap)
# levels(Idents(ctrl_filtered))[levels(Idents(ctrl_filtered)) %in% c("TC", "ASP")] <- "ASP+TC" # 合并ASP和TC
aver_expr_mat <- get_averexpr_mat_cluster(ctrl_filtered)

#从asp vs tr45数据集
highexp_genes <- read.csv("./data_tables/DEGs_from_smartSeq/Pro vs Asp.csv", header = T, row.names = 1)
highexp_genes[is.na(highexp_genes)] <-  0
PCgenes <- highexp_genes[highexp_genes$baseMean>1000 &
                            highexp_genes$log2FoldChange>0.5,]
ASPgenes <- highexp_genes[highexp_genes$baseMean>1000 &
                            highexp_genes$log2FoldChange<(-0.5),]
#ASP,log2FoldChange<(-0.5)    Tr45,log2FoldChange>0.5 baseMean>1000

PCgenes <- intersect(rownames(PCgenes),rownames(aver_expr_mat))
Tr45highexpr <- pheatmap(aver_expr_mat[PCgenes,], cluster_cols=F, scale = "row",cluster_rows = T, show_rownames = F, color = colorRampPalette(c("#1E90FF", "white", "#ff2121"))(400), angle_col = 45, border_color = NA, main = "Tr45highexpr Heatmap")


dd <- caret::preProcess(t(aver_expr_mat[PCgenes,])) %>%
  predict(t(aver_expr_mat[PCgenes,])) %>% t()
          
pheatmap(dd, cluster_cols=F, scale = "none", cluster_rows = T, show_rownames = F, color = colorRampPalette(c("#1E90FF", "white", "#ff2121"))(400), angle_col = 45, border_color = NA, main = "Tr45highexpr Heatmap")


data = colSums(dd>1)

ggplot(data.frame(num = data, cluster = names(data))) + geom_bar(aes(cluster, fill = cluster, weight = num)) + bartheme


# ggsave(filename = paste0("ASP_tr45highexpr Heatmap",".png"), device = png, height = 8, width = 12, plot = Tr45highexpr)
df1 = data.frame(list(colSums(dd>1))) %>% lapply(., function(vec){(vec-min(vec))/(max(vec)-min(vec))}) %>% data.frame()
colnames(df1) <- list('high expr counts')
df1$label <- colnames(dd)

df2 = data.frame(list(colSums(dd))) %>% lapply(., function(vec){(vec-min(vec))/(max(vec)-min(vec))}) %>% data.frame()
colnames(df2) <- list('average expression')
df2$label <- colnames(dd)
library(ggnewscale)
names(data)
[1] "ASP" "DB"  "DT"  "SB"  "PC"  "TC"  "VB"  "LT"  "GB" 
ggplot(data = reshape2::melt(position))+
  geom_line(aes(x=variable,y=factor(value),group=index, size=rep(reshape2::melt(df)$value,2)^2,color=..size..), alpha=1)+ scale_size(range = c(1,5)) + scale_color_gradient(low = 'lightgrey', high = "#1E90FF") + new_scale_color() +
  geom_line(aes(x=variable,y=factor(value),group=index, size=rep(reshape2::melt(df2)$value,2)^2,color=..size..), alpha=0.5)+ scale_size(range = c(1,5)) + scale_color_gradient(low = 'lightgrey', high = "#FF2121") + new_scale_color() +
  geom_point(mapping = aes(x=variable,y=factor(value),color=cell_type),size=7)+ scale_y_discrete(labels=names(data), position = "right") + scale_x_discrete(expand = c(0.05,0.05))+ scale_color_manual(values=colors_list) + theme_void() +theme(axis.text.y.right = element_text())
Using cell_type, index as id variables
Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
Please use `linewidth` instead.Scale for size is already present.
Adding another scale for size, which will replace the existing scale.

draw dendrogram for PC clusters

ggplot(data = plotdata) +
  geom_segment(aes(
    x = -2,
    y = 4,
    xend = y,
    yend = x,
    size = `average expression`^2,
    color = ..size..
  ),
  alpha = 0.8) + scale_size(range = c(1, 5)) + scale_color_gradient(low = '#ffffff', high = "#fd9999") + new_scale_color() +
  geom_segment(aes(
    x = -2,
    y = 4,
    xend = y,
    yend = x,
    size = `high expr counts`^2,
    color = ..size..
  ),
  alpha = 0.6) + scale_size(range = c(1, 5)) + scale_color_gradient(low = '#ffffff', high = "#b1d6fb") + new_scale_color() +
  geom_point(mapping = aes(x = y,
                           y = x,
                           color = label),
             size = 7) + geom_text(aes(x = y, y = x, label = label), size = 4) + geom_point(aes(x =
                                                                                                  -2, y = 4), color = 'lightgrey', size = 7) +
  scale_y_discrete(labels = plotdata$label, position = "right") + scale_x_discrete(expand = c(0.05, 0.05)) +
  scale_color_manual(values = color_mapping[plotdata$label]) +
  geom_segment(aes(
    x = y * 2 + 0.1,
    y = x,
    xend = yend * 2 + 0.1,
    yend = xend
  ),
  segment(ddata)) +
  theme_void() + theme(axis.text.y.right = element_text())
Scale for size is already present.
Adding another scale for size, which will replace the existing scale.

additional heatmap

pheatmap(corrmat, color = colorRampPalette(c("#1E90FF", "white", "#ff2121"))(400), border_color = NA, cluster_rows = T, cluster_cols = T, angle_col = 0, main = "Correlation Heatmap")

baseline Tr45

baseline ASP

TC

```r
aver_expr_mat <- get_averexpr_mat_cluster(TC)
colnames(aver_expr_mat) <- levels(TC@active.ident)

#从asp vs tr45数据集
all_genes <- read.csv(\./DEGs_from_smartSeq/Pro vs Asp.csv\, header = T,row.names = 1)
all_genes[is.na(all_genes)] <-  0
ASPgenes <- all_genes[all_genes$baseMean>100 & all_genes$padj<0.01 & all_genes$log2FoldChange<(-0.5),] #ASP,log2FoldChange<(-0.5)    Tr45,log2FoldChange>0.5 baseMean>1000
ASPgenes <- rownames(ASPgenes)
ASPgenes <- intersect(ASPgenes,rownames(TCsubMarkers))

Tr45highexpr <- pheatmap(aver_expr_mat[ASPgenes,], cluster_cols=F, scale = \row\,cluster_rows = T, show_rownames = F, color = colorRampPalette(c(\white\, \#ff2121\))(400), angle_col = 45, border_color = NA, main = \ASP_Tr45highexpr Heatmap\)

<!-- rnb-source-end -->

<!-- rnb-chunk-end -->


<!-- rnb-text-begin -->



# 比较SMARTseq和scRNA-seq marker基因的重合个数
## ASP

<!-- rnb-text-end -->


<!-- rnb-chunk-begin -->


```{=html}

<!-- rnb-htmlwidget-begin eyJkZXBlbmRlbmNpZXMiOlt7Im5hbWUiOiJodG1sd2lkZ2V0cyIsInZlcnNpb24iOiIxLjUuNCIsInNyYyI6eyJmaWxlIjoid3d3In0sIm1ldGEiOltdLCJzY3JpcHQiOiJodG1sd2lkZ2V0cy5qcyIsInN0eWxlc2hlZXQiOltdLCJoZWFkIjpbXSwiYXR0YWNobWVudCI6W10sInBhY2thZ2UiOiJodG1sd2lkZ2V0cyIsImFsbF9maWxlcyI6dHJ1ZX0seyJuYW1lIjoicGxvdGx5LWJpbmRpbmciLCJ2ZXJzaW9uIjoiNC4xMC4wIiwic3JjIjp7ImZpbGUiOiJodG1sd2lkZ2V0cyJ9LCJtZXRhIjpbXSwic2NyaXB0IjoicGxvdGx5LmpzIiwic3R5bGVzaGVldCI6W10sImhlYWQiOltdLCJhdHRhY2htZW50IjpbXSwicGFja2FnZSI6InBsb3RseSIsImFsbF9maWxlcyI6ZmFsc2V9LHsibmFtZSI6InR5cGVkYXJyYXkiLCJ2ZXJzaW9uIjoiMC4xIiwic3JjIjp7ImZpbGUiOiJodG1sd2lkZ2V0cy9saWIvdHlwZWRhcnJheSJ9LCJtZXRhIjpbXSwic2NyaXB0IjoidHlwZWRhcnJheS5taW4uanMiLCJzdHlsZXNoZWV0IjpbXSwiaGVhZCI6W10sImF0dGFjaG1lbnQiOltdLCJwYWNrYWdlIjoicGxvdGx5IiwiYWxsX2ZpbGVzIjpmYWxzZX0seyJuYW1lIjoianF1ZXJ5IiwidmVyc2lvbiI6IjMuNS4xIiwic3JjIjp7ImZpbGUiOiJsaWIvanF1ZXJ5In0sIm1ldGEiOltdLCJzY3JpcHQiOiJqcXVlcnkubWluLmpzIiwic3R5bGVzaGVldCI6W10sImhlYWQiOltdLCJhdHRhY2htZW50IjpbXSwicGFja2FnZSI6ImNyb3NzdGFsayIsImFsbF9maWxlcyI6dHJ1ZX0seyJuYW1lIjoiY3Jvc3N0YWxrIiwidmVyc2lvbiI6IjEuMS4xIiwic3JjIjp7ImZpbGUiOiJ3d3cifSwibWV0YSI6W10sInNjcmlwdCI6ImpzL2Nyb3NzdGFsay5taW4uanMiLCJzdHlsZXNoZWV0IjoiY3NzL2Nyb3NzdGFsay5jc3MiLCJoZWFkIjpbXSwiYXR0YWNobWVudCI6W10sInBhY2thZ2UiOiJjcm9zc3RhbGsiLCJhbGxfZmlsZXMiOnRydWV9LHsibmFtZSI6InBsb3RseS1odG1sd2lkZ2V0cy1jc3MiLCJ2ZXJzaW9uIjoiMi41LjEiLCJzcmMiOnsiZmlsZSI6Imh0bWx3aWRnZXRzL2xpYi9wbG90bHlqcyJ9LCJtZXRhIjpbXSwic2NyaXB0IjpbXSwic3R5bGVzaGVldCI6InBsb3RseS1odG1sd2lkZ2V0cy5jc3MiLCJoZWFkIjpbXSwiYXR0YWNobWVudCI6W10sInBhY2thZ2UiOiJwbG90bHkiLCJhbGxfZmlsZXMiOmZhbHNlfSx7Im5hbWUiOiJwbG90bHktbWFpbiIsInZlcnNpb24iOiIyLjUuMSIsInNyYyI6eyJmaWxlIjoiaHRtbHdpZGdldHMvbGliL3Bsb3RseWpzIn0sIm1ldGEiOltdLCJzY3JpcHQiOiJwbG90bHktbGF0ZXN0Lm1pbi5qcyIsInN0eWxlc2hlZXQiOltdLCJoZWFkIjpbXSwiYXR0YWNobWVudCI6W10sInBhY2thZ2UiOiJwbG90bHkiLCJhbGxfZmlsZXMiOmZhbHNlfV0sIm1ldGFkYXRhIjp7ImNsYXNzZXMiOlsicGxvdGx5IiwiaHRtbHdpZGdldCJdLCJzaXppbmdQb2xpY3kiOnsiZGVmYXVsdFdpZHRoIjpbIjEwMCUiXSwiZGVmYXVsdEhlaWdodCI6WzQwMF0sInBhZGRpbmciOlswXSwidmlld2VyIjp7ImRlZmF1bHRXaWR0aCI6W10sImRlZmF1bHRIZWlnaHQiOltdLCJwYWRkaW5nIjpbXSwiZmlsbCI6W3RydWVdLCJzdXBwcmVzcyI6W2ZhbHNlXSwicGFuZUhlaWdodCI6W119LCJicm93c2VyIjp7ImRlZmF1bHRXaWR0aCI6W10sImRlZmF1bHRIZWlnaHQiOltdLCJwYWRkaW5nIjpbXSwiZmlsbCI6W3RydWVdLCJleHRlcm5hbCI6W2ZhbHNlXX0sImtuaXRyIjp7ImRlZmF1bHRXaWR0aCI6W10sImRlZmF1bHRIZWlnaHQiOltdLCJmaWd1cmUiOlt0cnVlXX0sInZpZXdlci5wYWRkaW5nIjpbMF0sInZpZXdlci5maWxsIjpbdHJ1ZV19fX0= -->

<!-- htmlwidget-container-begin -->
<div id="htmlwidget-e4450e7f18c39ad5e98d" style="width:504px;height:504px;" class="plotly html-widget"></div>
<!-- htmlwidget-container-end -->
<script type="application/json" data-for="htmlwidget-e4450e7f18c39ad5e98d">{"x":{"visdat":{"460d769c0a06":["function () ","plotlyVisDat"]},"cur_data":"460d769c0a06","attrs":{"460d769c0a06":{"x":["DB","DT","SB","PC","TC","VB","LT","GB","ASP"],"y":[7,6,5,25,10,16,24,57,19],"name":"ASP_normalized","alpha_stroke":1,"sizes":[10,100],"spans":[1,20],"type":"bar"},"460d769c0a06.1":{"x":["DB","DT","SB","PC","TC","VB","LT","GB","ASP"],"y":[7,8,4,23,16,13,28,78,22],"name":"notchctrl","alpha_stroke":1,"sizes":[10,100],"spans":[1,20],"type":"bar","inherit":true},"460d769c0a06.2":{"x":["DB","DT","SB","PC","TC","VB","LT","GB","ASP"],"y":[4,6,5,19,12,16,30,76,20],"name":"ASP_TPM","alpha_stroke":1,"sizes":[10,100],"spans":[1,20],"type":"bar","inherit":true}},"layout":{"margin":{"b":40,"l":60,"t":25,"r":10},"title":"ASPtop4000","xaxis":{"domain":[0,1],"automargin":true,"title":[],"type":"category","categoryorder":"array","categoryarray":["ASP","DB","DT","GB","LT","PC","SB","TC","VB"]},"yaxis":{"domain":[0,1],"automargin":true,"title":[]},"hovermode":"closest","showlegend":true},"source":"A","config":{"modeBarButtonsToAdd":["hoverclosest","hovercompare"],"showSendToCloud":false},"data":[{"x":["DB","DT","SB","PC","TC","VB","LT","GB","ASP"],"y":[7,6,5,25,10,16,24,57,19],"name":"ASP_normalized","type":"bar","marker":{"color":"rgba(31,119,180,1)","line":{"color":"rgba(31,119,180,1)"}},"error_y":{"color":"rgba(31,119,180,1)"},"error_x":{"color":"rgba(31,119,180,1)"},"xaxis":"x","yaxis":"y","frame":null},{"x":["DB","DT","SB","PC","TC","VB","LT","GB","ASP"],"y":[7,8,4,23,16,13,28,78,22],"name":"notchctrl","type":"bar","marker":{"color":"rgba(255,127,14,1)","line":{"color":"rgba(255,127,14,1)"}},"error_y":{"color":"rgba(255,127,14,1)"},"error_x":{"color":"rgba(255,127,14,1)"},"xaxis":"x","yaxis":"y","frame":null},{"x":["DB","DT","SB","PC","TC","VB","LT","GB","ASP"],"y":[4,6,5,19,12,16,30,76,20],"name":"ASP_TPM","type":"bar","marker":{"color":"rgba(44,160,44,1)","line":{"color":"rgba(44,160,44,1)"}},"error_y":{"color":"rgba(44,160,44,1)"},"error_x":{"color":"rgba(44,160,44,1)"},"xaxis":"x","yaxis":"y","frame":null}],"highlight":{"on":"plotly_click","persistent":false,"dynamic":false,"selectize":false,"opacityDim":0.2,"selected":{"opacity":1},"debounce":0},"shinyEvents":["plotly_hover","plotly_click","plotly_selected","plotly_relayout","plotly_brushed","plotly_brushing","plotly_clickannotation","plotly_doubleclick","plotly_deselect","plotly_afterplot","plotly_sunburstclick"],"base_url":"https://plot.ly"},"evals":[],"jsHooks":[]}</script>
<!-- htmlwidget-sizing-policy-base64 PHNjcmlwdCB0eXBlPSJhcHBsaWNhdGlvbi9odG1sd2lkZ2V0LXNpemluZyIgZGF0YS1mb3I9Imh0bWx3aWRnZXQtZTQ0NTBlN2YxOGMzOWFkNWU5OGQiPnsidmlld2VyIjp7IndpZHRoIjoiMTAwJSIsImhlaWdodCI6NDAwLCJwYWRkaW5nIjowLCJmaWxsIjp0cnVlfSwiYnJvd3NlciI6eyJ3aWR0aCI6IjEwMCUiLCJoZWlnaHQiOjQwMCwicGFkZGluZyI6MCwiZmlsbCI6dHJ1ZX19PC9zY3JpcHQ+ -->

<!-- rnb-htmlwidget-end -->

PC

refdata2 <- read.csv("./data_tables/DEGs_from_smartSeq/nomalized_expr_tr4Tr5Tr5_2.csv",row.names = 1)
cluster_info <- Idents(ctrl_filtered) %>% levels()
# refdata2 <- read.csv("~/single cell-atlas of fly trachea/ASP_bulkRNAseq/Tr45_normalized_counts.csv",row.names = 1)
refdata2 <- as.matrix(rowMeans(refdata2)) 
refdata2 <- as.matrix(as.matrix(refdata2[order(refdata2,decreasing = T),])[1:800,]) 
geneset2 <- intersect(VariableFeatures(ctrl_filtered), rownames(refdata2)) 
inter <- lapply(cluster_info, func, geneset2)

plot_ly(
  x = cluster_info,
  y = as.numeric(inter),
  name = "asptrdataset", type = "bar") %>% layout(title = "PCtop800")

pheatmap(aver_expr_mat[geneset2,], cluster_cols=F, scale = "none",cluster_rows = T, show_rownames = F, color = colorRampPalette(c( "white", "#ff2121"))(400), angle_col = 45, border_color = NA, main = "PCtop800 Heatmap")
library(UpSetR)
func22 <- function(i, feature){
  intersect(ctrl_markers[ctrl_markers$cluster == i,]$gene, feature)
}

data =  lapply(cluster_info, func22, geneset2)
names(data) <- cluster_info
upset(fromList(data),nsets = length(data), sets = cluster_info)
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0KZ2V0d2QoKQprbml0cjo6b3B0c19rbml0JHNldChyb290LmRpciA9ICIvaG9tZS96anUvdGlhbmZlbmcvc2luZ2xlX2NlbGxfYXRsYXMiKQojIHNldHdkKCIvaG9tZS96anUvdGlhbmZlbmcvc2luZ2xlX2NlbGxfYXRsYXMiKQojIGdldHdkKCkKYGBgCgpgYGB7cn0Kc291cmNlKCIuL3V0aWxzL3RpYW5mZW5nUndyYXBwZXJzLlIiKQogCiPojrflj5blubPlnYfooajovr7nn6npmLUKYXZlcl9leHByX21hdCA8LSBnZXRfYXZlcmV4cHJfbWF0X2NsdXN0ZXIoY3RybF9maWx0ZXJlZCkKYnVsa19leHByX21hdCA8LSByZWFkLmNzdigiLi9kYXRhX3RhYmxlcy9ERUdzX2Zyb21fc21hcnRTZXEvbm9tYWxpemVkX2V4cHJfdHI0VHI1VHI1XzIuY3N2Iixyb3cubmFtZXMgPSAxKQpidWxrX2V4cHJfbWF0IDwtIGJ1bGtfZXhwcl9tYXRbLCEoY29sbmFtZXMoYnVsa19leHByX21hdCklaW4lIlRyNV8yIildCmNvbG5hbWVzKGF2ZXJfZXhwcl9tYXQpIDwtIGxldmVscyhjdHJsX2ZpbHRlcmVkQGFjdGl2ZS5pZGVudCkKI+mAiemrmOW3ruW8guihqOi+vgojIGRpZmZfZ2VuZXMgPC0gaW50ZXJzZWN0KGN0cmxfZmlsdGVyZWRAYXNzYXlzW1siU0NUIl1dQHZhci5mZWF0dXJlcywgcm93bmFtZXMoYnVsa19leHByX21hdCkpCmRpZmZfZ2VuZXMgPC0gaW50ZXJzZWN0KHJvd25hbWVzKGF2ZXJfZXhwcl9tYXQpLCByb3duYW1lcyhidWxrX2V4cHJfbWF0KSkKYXZlcl9leHByX21hdCA8LSBhdmVyX2V4cHJfbWF0W2RpZmZfZ2VuZXMsXQpidWxrX2V4cHJfbWF0IDwtIGJ1bGtfZXhwcl9tYXRbZGlmZl9nZW5lcyxdCiMgbm9ybWFsaXplZF9jb3VudHMgPC0gIG5vcm1hbGl6ZWRfY291bnRzW2RpZmZfZ2VuZXMsXQoKY29ybWF0IDwtIGNvcihhdmVyX2V4cHJfbWF0LGJ1bGtfZXhwcl9tYXQsIG1ldGhvZCA9ICJzcGVhcm1hbiIpCnBoZWF0bWFwKGNvcm1hdCwgY29sb3IgPSBjb2xvclJhbXBQYWxldHRlKGMoIiMxRTkwRkYiLCAid2hpdGUiLCAiI2ZmMjEyMSIpKSg0MDApLCBib3JkZXJfY29sb3IgPSBOQSwgY2x1c3Rlcl9yb3dzID0gVCwgY2x1c3Rlcl9jb2xzID0gVCwgYW5nbGVfY29sID0gMCwgbWFpbiA9ICJDb3JyZWxhdGlvbiBIZWF0bWFwIikKCmBgYAojIEFTUCBidWxrIFJOQXNlcQpgYGB7cn0KYXZlcl9leHByX21hdCA8LSBnZXRfYXZlcmV4cHJfbWF0X2NsdXN0ZXIoY3RybF9maWx0ZXJlZCkKQVNQX2J1bGtfZXhwX21hdDEgPC0gcmVhZC5jc3YoImRhdGFfdGFibGVzL0RFR3NfZnJvbV9zbWFydFNlcS9BU1Bfbm9ybWFsaXplZF9jb3VudHMvYXNwX25vcm1hbGl6ZWRfY291bnRzLmNzdiIscm93Lm5hbWVzID0gMSkgICU+JSBhcy5tYXRyaXgoKQpBU1BfYnVsa19leHBfbWF0MiA8LSByZWFkLmNzdigiZGF0YV90YWJsZXMvREVHc19mcm9tX3NtYXJ0U2VxL0FTUF9ub3JtYWxpemVkX2NvdW50cy9BU1BfVFBNLmNzdiIscm93Lm5hbWVzID0gMSkgICU+JSBhcy5tYXRyaXgoKQpBU1BfYnVsa19leHBfbWF0MyA8LSByZWFkLmNzdigiZGF0YV90YWJsZXMvREVHc19mcm9tX3NtYXJ0U2VxL0FTUF9ub3JtYWxpemVkX2NvdW50cy9ub3RjaGRhdGFzZXRfbm9ybWFsaXplZF9jb3VudHMuY3N2Iixyb3cubmFtZXMgPSAxKSAgJT4lIGFzLm1hdHJpeCgpCgpkaWZmX2dlbmVzIDwtIFJlZHVjZShpbnRlcnNlY3QsIGxpc3QoY3RybF9maWx0ZXJlZEBhc3NheXNbWyJTQ1QiXV1AdmFyLmZlYXR1cmVzLAogICAgICAgICAgICAgICAgICAgICAgICByb3duYW1lcyhBU1BfYnVsa19leHBfbWF0MSkscm93bmFtZXMoQVNQX2J1bGtfZXhwX21hdDIpLAogICAgICAgICAgICAgICAgICAgICAgICByb3duYW1lcyhBU1BfYnVsa19leHBfbWF0MykpKQoKYXZlcl9leHByX21hdCA8LSBhdmVyX2V4cHJfbWF0W2RpZmZfZ2VuZXMsXQpBU1BfYnVsa19leHByX21hdCA8LSBjYmluZChBU1BfYnVsa19leHBfbWF0MVtkaWZmX2dlbmVzLF0sQVNQX2J1bGtfZXhwX21hdDJbZGlmZl9nZW5lcyxdLAogICAgICAgICAgICAgICAgICAgICAgIEFTUF9idWxrX2V4cF9tYXQzW2RpZmZfZ2VuZXMsXSkKY29sbmFtZXMoQVNQX2J1bGtfZXhwcl9tYXQpIDwtIGMoIkFTUDEiLCJBU1AyIiwiQVNQMyIpCmNvcm1hdCA8LSBjb3IoYXZlcl9leHByX21hdCxBU1BfYnVsa19leHByX21hdCwgbWV0aG9kID0gInNwZWFybWFuIikKcGhlYXRtYXAoY29ybWF0LCBjb2xvciA9IGNvbG9yUmFtcFBhbGV0dGUoYygiIzFFOTBGRiIsICJ3aGl0ZSIsICIjZmYyMTIxIikpKDQwMCksIGJvcmRlcl9jb2xvciA9IE5BLCBjbHVzdGVyX3Jvd3MgPSBULCBjbHVzdGVyX2NvbHMgPSBULCBhbmdsZV9jb2wgPSAwLCBtYWluID0gIkNvcnJlbGF0aW9uIEhlYXRtYXAiKQpgYGAKCgoKCgojc21hcnRzZXEg5Lqk5Y+J6aqM6K+BIFBDIGluIHNjUk5BLXNlcQpgYGB7cn0KZGVncyA8LSByZWFkLmNzdigiLi9kYXRhX3RhYmxlcy9ERUdzX2Zyb21fc21hcnRTZXEvdXBfREVHc2xpc3QuY3N2IixoZWFkZXIgPSBGQUxTRSkKY3RybF9tYXJrZXJzIDwtIHJlYWQuY3N2KCIuL2RhdGFfdGFibGVzL2N0cmxfbWFya2Vyc19maWcxLmNzdiIsIHJvdy5uYW1lcyA9IDEpCmRobShpbnRlcnNlY3QoZGVncyRWMSxyb3duYW1lcyhjdHJsX21hcmtlcnMpKSwgY3RybF9maWx0ZXJlZCkKCiNnZ3NhdmUoZmlsZW5hbWUgPSBwYXN0ZTAoImhpZ2hleHByX3RyNSIsIi5wbmciKSwgZGV2aWNlID0gcG5nLCBoZWlnaHQgPSA4LCB3aWR0aCA9IDEyLCBwbG90ID0gaGlnaGV4cHJoZWF0bWFwKQpgYGAKCgpgYGB7cn0KIyBsZXZlbHMoSWRlbnRzKGN0cmxfZmlsdGVyZWQpKVtsZXZlbHMoSWRlbnRzKGN0cmxfZmlsdGVyZWQpKSAlaW4lIGMoIlRDIiwgIkFTUCIpXSA8LSAiQVNQK1RDIiAjIOWQiOW5tkFTUOWSjFRDCmF2ZXJfZXhwcl9tYXQgPC0gZ2V0X2F2ZXJleHByX21hdF9jbHVzdGVyKGN0cmxfZmlsdGVyZWQpCgoj5LuOYXNwIHZzIHRyNDXmlbDmja7pm4YKaGlnaGV4cF9nZW5lcyA8LSByZWFkLmNzdigiLi9kYXRhX3RhYmxlcy9ERUdzX2Zyb21fc21hcnRTZXEvUHJvIHZzIEFzcC5jc3YiLCBoZWFkZXIgPSBULCByb3cubmFtZXMgPSAxKQpoaWdoZXhwX2dlbmVzW2lzLm5hKGhpZ2hleHBfZ2VuZXMpXSA8LSAgMApQQ2dlbmVzIDwtIGhpZ2hleHBfZ2VuZXNbaGlnaGV4cF9nZW5lcyRiYXNlTWVhbj4xMDAwICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhpZ2hleHBfZ2VuZXMkbG9nMkZvbGRDaGFuZ2U+MC41LF0KQVNQZ2VuZXMgPC0gaGlnaGV4cF9nZW5lc1toaWdoZXhwX2dlbmVzJGJhc2VNZWFuPjEwMDAgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgaGlnaGV4cF9nZW5lcyRsb2cyRm9sZENoYW5nZTwoLTAuNSksXQojQVNQLGxvZzJGb2xkQ2hhbmdlPCgtMC41KSAgICBUcjQ1LGxvZzJGb2xkQ2hhbmdlPjAuNSBiYXNlTWVhbj4xMDAwCgpQQ2dlbmVzIDwtIGludGVyc2VjdChyb3duYW1lcyhQQ2dlbmVzKSxyb3duYW1lcyhhdmVyX2V4cHJfbWF0KSkKVHI0NWhpZ2hleHByIDwtIHBoZWF0bWFwKGF2ZXJfZXhwcl9tYXRbUENnZW5lcyxdLCBjbHVzdGVyX2NvbHM9Riwgc2NhbGUgPSAicm93IixjbHVzdGVyX3Jvd3MgPSBULCBzaG93X3Jvd25hbWVzID0gRiwgY29sb3IgPSBjb2xvclJhbXBQYWxldHRlKGMoIiMxRTkwRkYiLCAid2hpdGUiLCAiI2ZmMjEyMSIpKSg0MDApLCBhbmdsZV9jb2wgPSA0NSwgYm9yZGVyX2NvbG9yID0gTkEsIG1haW4gPSAiVHI0NWhpZ2hleHByIEhlYXRtYXAiKQoKZGQgPC0gY2FyZXQ6OnByZVByb2Nlc3ModChhdmVyX2V4cHJfbWF0W1BDZ2VuZXMsXSkpICU+JQogIHByZWRpY3QodChhdmVyX2V4cHJfbWF0W1BDZ2VuZXMsXSkpICU+JSB0KCkKICAgICAgICAgIApwaGVhdG1hcChkZCwgY2x1c3Rlcl9jb2xzPUYsIHNjYWxlID0gIm5vbmUiLCBjbHVzdGVyX3Jvd3MgPSBULCBzaG93X3Jvd25hbWVzID0gRiwgY29sb3IgPSBjb2xvclJhbXBQYWxldHRlKGMoIiMxRTkwRkYiLCAid2hpdGUiLCAiI2ZmMjEyMSIpKSg0MDApLCBhbmdsZV9jb2wgPSA0NSwgYm9yZGVyX2NvbG9yID0gTkEsIG1haW4gPSAiVHI0NWhpZ2hleHByIEhlYXRtYXAiKQoKZGF0YSA9IGNvbFN1bXMoZGQ+MSkKCmdncGxvdChkYXRhLmZyYW1lKG51bSA9IGRhdGEsIGNsdXN0ZXIgPSBuYW1lcyhkYXRhKSkpICsgZ2VvbV9iYXIoYWVzKGNsdXN0ZXIsIGZpbGwgPSBjbHVzdGVyLCB3ZWlnaHQgPSBudW0pKSArIGJhcnRoZW1lCgojIGdnc2F2ZShmaWxlbmFtZSA9IHBhc3RlMCgiQVNQX3RyNDVoaWdoZXhwciBIZWF0bWFwIiwiLnBuZyIpLCBkZXZpY2UgPSBwbmcsIGhlaWdodCA9IDgsIHdpZHRoID0gMTIsIHBsb3QgPSBUcjQ1aGlnaGV4cHIpCmBgYAoKYGBge3J9CmRmMSA9IGRhdGEuZnJhbWUobGlzdChjb2xTdW1zKGRkPjEpKSkgJT4lIGxhcHBseSguLCBmdW5jdGlvbih2ZWMpeyh2ZWMtbWluKHZlYykpLyhtYXgodmVjKS1taW4odmVjKSl9KSAlPiUgZGF0YS5mcmFtZSgpCmNvbG5hbWVzKGRmMSkgPC0gbGlzdCgnaGlnaCBleHByIGNvdW50cycpCmRmMSRsYWJlbCA8LSBjb2xuYW1lcyhkZCkKCmRmMiA9IGRhdGEuZnJhbWUobGlzdChjb2xTdW1zKGRkKSkpICU+JSBsYXBwbHkoLiwgZnVuY3Rpb24odmVjKXsodmVjLW1pbih2ZWMpKS8obWF4KHZlYyktbWluKHZlYykpfSkgJT4lIGRhdGEuZnJhbWUoKQpjb2xuYW1lcyhkZjIpIDwtIGxpc3QoJ2F2ZXJhZ2UgZXhwcmVzc2lvbicpCmRmMiRsYWJlbCA8LSBjb2xuYW1lcyhkZCkKYGBgCgpgYGB7cn0KbGlicmFyeShnZ25ld3NjYWxlKQpwb3NpdGlvbiA8LSBkYXRhLmZyYW1lKHJlcCg0LDkpLCBzZXEoMCw4LGxlbmd0aC5vdXQ9OSkpCnBvc2l0aW9uJGNlbGxfdHlwZSA8LSByZXAobmFtZXMoZGF0YSksMSkKcG9zaXRpb24kaW5kZXggPC0gcm93bmFtZXMocG9zaXRpb24pCgpjb2xuYW1lcyhwb3NpdGlvbikgPC0gbGlzdCgnbGVmdCcsJ3JpZ2h0JywnY2VsbF90eXBlJywnaW5kZXgnKQpyZXNoYXBlMjo6bWVsdChwb3NpdGlvbikKcG9zaXRpb24KZ2dwbG90KGRhdGEgPSByZXNoYXBlMjo6bWVsdChwb3NpdGlvbikpKwogIGdlb21fbGluZShhZXMoeD12YXJpYWJsZSx5PWZhY3Rvcih2YWx1ZSksZ3JvdXA9aW5kZXgsIHNpemU9cmVwKHJlc2hhcGUyOjptZWx0KGRmKSR2YWx1ZSwyKV4yLGNvbG9yPS4uc2l6ZS4uKSwgYWxwaGE9MSkrIHNjYWxlX3NpemUocmFuZ2UgPSBjKDEsNSkpICsgc2NhbGVfY29sb3JfZ3JhZGllbnQobG93ID0gJ2xpZ2h0Z3JleScsIGhpZ2ggPSAiIzFFOTBGRiIpICsgbmV3X3NjYWxlX2NvbG9yKCkgKwogIGdlb21fbGluZShhZXMoeD12YXJpYWJsZSx5PWZhY3Rvcih2YWx1ZSksZ3JvdXA9aW5kZXgsIHNpemU9cmVwKHJlc2hhcGUyOjptZWx0KGRmMikkdmFsdWUsMileMixjb2xvcj0uLnNpemUuLiksIGFscGhhPTAuNSkrIHNjYWxlX3NpemUocmFuZ2UgPSBjKDEsNSkpICsgc2NhbGVfY29sb3JfZ3JhZGllbnQobG93ID0gJ2xpZ2h0Z3JleScsIGhpZ2ggPSAiI0ZGMjEyMSIpICsgbmV3X3NjYWxlX2NvbG9yKCkgKwogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4PXZhcmlhYmxlLHk9ZmFjdG9yKHZhbHVlKSxjb2xvcj1jZWxsX3R5cGUpLHNpemU9NykrIHNjYWxlX3lfZGlzY3JldGUobGFiZWxzPW5hbWVzKGRhdGEpLCBwb3NpdGlvbiA9ICJyaWdodCIpICsgc2NhbGVfeF9kaXNjcmV0ZShleHBhbmQgPSBjKDAuMDUsMC4wNSkpKyBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWNvbG9yc19saXN0KSArIHRoZW1lX3ZvaWQoKSArdGhlbWUoYXhpcy50ZXh0LnkucmlnaHQgPSBlbGVtZW50X3RleHQoKSkKYGBgCgojIyMgZHJhdyBkZW5kcm9ncmFtIGZvciBQQyBjbHVzdGVycwpgYGB7cn0KbGlicmFyeShnZ2RlbmRybykKY29ycm1hdCA8LSBjb3IoYXZlcl9leHByX21hdCwgbWV0aG9kID0gInNwZWFybWFuIikKZGlzdG1hdCA8LSAxIC0gY29ycm1hdApkaXN0bWF0ICU8PiUgYXMuZGlzdCgpICMgdHJhbnNmb3JtIHRvIGRpc3Qgb2JqZWN0CmRkYXRhIDwtIGhjbHVzdChkaXN0bWF0KSAlPiUgYXMuZGVuZHJvZ3JhbSgpICU+JSBkZW5kcm9fZGF0YSh0eXBlID0gInJlY3RhbmdsZSIpCiMgZ2dkZW5kcm9ncmFtKGhjbHVzdChkaXN0bWF0KSwgcm90YXRlID0gRkFMU0UsIHNpemUgPSAyKQpnZ3Bsb3Qoc2VnbWVudChkZGF0YSkpICsgCiAgZ2VvbV9zZWdtZW50KGFlcyh4ID0geCwgeSA9IHksIHhlbmQgPSB4ZW5kLCB5ZW5kID0geWVuZCkpICsgCiAgY29vcmRfZmxpcCgpICsgCiAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMC4yLCAwKSkKCmNvbG9yX21hcHBpbmcgPC0gY29sb3JzX2xpc3RbMTo5XQpuYW1lcyhjb2xvcl9tYXBwaW5nKSA8LSBjdHJsX2ZpbHRlcmVkJGNlbGx0eXBlICU+JSBsZXZlbHMoKQoKcG9zaXRpb24gPC0gZGRhdGFbWyJsYWJlbHMiXV0KcG9zaXRpb24kbGVmdCA8LSA0CnBsb3RkYXRhIDwtIFJlZHVjZShmdW5jdGlvbih4LCB5KXtpbm5lcl9qb2luKHgsIHksIGJ5PSdsYWJlbCcpfSwgbGlzdChwb3NpdGlvbiwgZGYxLCBkZjIpKQoKZ2dwbG90KGRhdGEgPSBwbG90ZGF0YSkgKwogIGdlb21fc2VnbWVudChhZXMoCiAgICB4ID0gLTIsCiAgICB5ID0gNCwKICAgIHhlbmQgPSB5LAogICAgeWVuZCA9IHgsCiAgICBzaXplID0gYGF2ZXJhZ2UgZXhwcmVzc2lvbmBeMiwKICAgIGNvbG9yID0gLi5zaXplLi4KICApLAogIGFscGhhID0gMC44KSArIHNjYWxlX3NpemUocmFuZ2UgPSBjKDEsIDUpKSArIHNjYWxlX2NvbG9yX2dyYWRpZW50KGxvdyA9ICcjZmZmZmZmJywgaGlnaCA9ICIjZmQ5OTk5IikgKyBuZXdfc2NhbGVfY29sb3IoKSArCiAgZ2VvbV9zZWdtZW50KGFlcygKICAgIHggPSAtMiwKICAgIHkgPSA0LAogICAgeGVuZCA9IHksCiAgICB5ZW5kID0geCwKICAgIHNpemUgPSBgaGlnaCBleHByIGNvdW50c2BeMiwKICAgIGNvbG9yID0gLi5zaXplLi4KICApLAogIGFscGhhID0gMC42KSArIHNjYWxlX3NpemUocmFuZ2UgPSBjKDEsIDUpKSArIHNjYWxlX2NvbG9yX2dyYWRpZW50KGxvdyA9ICcjZmZmZmZmJywgaGlnaCA9ICIjYjFkNmZiIikgKyBuZXdfc2NhbGVfY29sb3IoKSArCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSB5LAogICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0geCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBsYWJlbCksCiAgICAgICAgICAgICBzaXplID0gNykgKyBnZW9tX3RleHQoYWVzKHggPSB5LCB5ID0geCwgbGFiZWwgPSBsYWJlbCksIHNpemUgPSA0KSArIGdlb21fcG9pbnQoYWVzKHggPQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC0yLCB5ID0gNCksIGNvbG9yID0gJ2xpZ2h0Z3JleScsIHNpemUgPSA3KSArCiAgc2NhbGVfeV9kaXNjcmV0ZShsYWJlbHMgPSBwbG90ZGF0YSRsYWJlbCwgcG9zaXRpb24gPSAicmlnaHQiKSArIHNjYWxlX3hfZGlzY3JldGUoZXhwYW5kID0gYygwLjA1LCAwLjA1KSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjb2xvcl9tYXBwaW5nW3Bsb3RkYXRhJGxhYmVsXSkgKwogIGdlb21fc2VnbWVudChhZXMoCiAgICB4ID0geSAqIDIgKyAwLjEsCiAgICB5ID0geCwKICAgIHhlbmQgPSB5ZW5kICogMiArIDAuMSwKICAgIHllbmQgPSB4ZW5kCiAgKSwKICBzZWdtZW50KGRkYXRhKSkgKwogIHRoZW1lX3ZvaWQoKSArIHRoZW1lKGF4aXMudGV4dC55LnJpZ2h0ID0gZWxlbWVudF90ZXh0KCkpCgoKCgpgYGAKIyMjIGFkZGl0aW9uYWwgaGVhdG1hcApgYGB7ciBmaWcud2lkdGg9NCwgZmlnLmhlaWdodD0zfQpwaGVhdG1hcChjb3JybWF0LCBjb2xvciA9IGNvbG9yUmFtcFBhbGV0dGUoYygiIzFFOTBGRiIsICJ3aGl0ZSIsICIjZmYyMTIxIikpKDQwMCksIGJvcmRlcl9jb2xvciA9IE5BLCBjbHVzdGVyX3Jvd3MgPSBULCBjbHVzdGVyX2NvbHMgPSBULCBhbmdsZV9jb2wgPSAwLCBtYWluID0gIkNvcnJlbGF0aW9uIEhlYXRtYXAiKQpgYGAKCgojIGJhc2VsaW5lIFRyNDUKYGBge3IgZmlnLmhlaWdodD00LCBmaWcud2lkdGg9Nn0KaGlnaGV4cF9nZW5lcyA8LSByZWFkLmNzdigiLi9kYXRhX3RhYmxlcy9ERUdzX2Zyb21fc21hcnRTZXEvVHI0IHZzIFRyNS5jc3YiLCBoZWFkZXIgPSBULHJvdy5uYW1lcyA9IDEpCmhpZ2hleHBfZ2VuZXNbaXMubmEoaGlnaGV4cF9nZW5lcyldIDwtICAwIApoaWdoZXhwX2dlbmVzIDwtIGhpZ2hleHBfZ2VuZXNbaGlnaGV4cF9nZW5lcyRiYXNlTWVhbj4yMDAwLF0gIyBUcjQ1LGxvZzJGb2xkQ2hhbmdlPjAuNSBiYXNlTWVhbj4xMDAw5a+55bqUMTkzLCAyMDAw5a+55bqUMTIwLDMwMDDlr7nlupQ4OO+8jDUwMDDlr7nlupQ1OCw2MDAw5a+55bqUNTHvvIwxMDAwMOWvueS6jjM0CmhpZ2hleHBfZ2VuZXMgPC0gcm93bmFtZXMoaGlnaGV4cF9nZW5lcykKbGVuZ3RoKGludGVyc2VjdChoaWdoZXhwX2dlbmVzLHJvd25hbWVzKGF2ZXJfZXhwcl9tYXQpKSkKVHI0NWhpZ2hleHByMiA8LSBwaGVhdG1hcChhdmVyX2V4cHJfbWF0W2ludGVyc2VjdChoaWdoZXhwX2dlbmVzLHJvd25hbWVzKGF2ZXJfZXhwcl9tYXQpKSxdLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSB1bmlxdWUoYyhzZXEoMCw0LCBsZW5ndGg9NDAwKSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfY29scz1GLCBzY2FsZSA9ICJub25lIixjbHVzdGVyX3Jvd3MgPSBULCBzaG93X3Jvd25hbWVzID0gRiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBjb2xvclJhbXBQYWxldHRlKGMoIndoaXRlIiwgIiNmZjIxMjEiKSkoNDAwKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgYW5nbGVfY29sID0gNDUsIGJvcmRlcl9jb2xvciA9IE5BLCBtYWluID0gImJhc2VsaW5lX3RyNDVoaWdoZXhwciBIZWF0bWFwIikKI2dnc2F2ZShmaWxlbmFtZSA9IHBhc3RlMCgiYmFzZWxpbmVfdHI0NWhpZ2hleHByIEhlYXRtYXAiLCIucG5nIiksIGRldmljZSA9IHBuZywgaGVpZ2h0ID0gOCwgd2lkdGggPSAxMiwgcGxvdCA9IFRyNDVoaWdoZXhwcjIpCmBgYAoKIyBiYXNlbGluZSBBU1AKYGBge3IgZmlnLmhlaWdodD00LCBmaWcud2lkdGg9Nn0KaGlnaGV4cF9nZW5lcyA8LSByZWFkLmNzdigiLi9kYXRhX3RhYmxlcy9ERUdzX2Zyb21fc21hcnRTZXEvUHJvIHZzIEFzcC5jc3YiLCBoZWFkZXIgPSBULHJvdy5uYW1lcyA9IDEpCmhpZ2hleHBfZ2VuZXNbaXMubmEoaGlnaGV4cF9nZW5lcyldIDwtICAwCmhpZ2hleHBfZ2VuZXMgPC0gaGlnaGV4cF9nZW5lc1toaWdoZXhwX2dlbmVzJGJhc2VNZWFuPjEwMDAsXQpoaWdoZXhwX2dlbmVzIDwtIHJvd25hbWVzKGhpZ2hleHBfZ2VuZXMpCmxlbmd0aChpbnRlcnNlY3QoaGlnaGV4cF9nZW5lcyxyb3duYW1lcyhhdmVyX2V4cHJfbWF0KSkpCnBoZWF0bWFwKGF2ZXJfZXhwcl9tYXRbaW50ZXJzZWN0KGhpZ2hleHBfZ2VuZXMscm93bmFtZXMoYXZlcl9leHByX21hdCkpLF0sIAogICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHVuaXF1ZShjKHNlcSgwLDQsIGxlbmd0aD00MDApKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9jb2xzPUYsIHNjYWxlID0gIm5vbmUiLGNsdXN0ZXJfcm93cyA9IFQsIHNob3dfcm93bmFtZXMgPSBGLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IGNvbG9yUmFtcFBhbGV0dGUoYygid2hpdGUiLCAiI2ZmMjEyMSIpKSg0MDApLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBhbmdsZV9jb2wgPSA0NSwgYm9yZGVyX2NvbG9yID0gTkEsIG1haW4gPSAiYmFzZWxpbmVfQXNwaGlnaGV4cHIgSGVhdG1hcCIpCiNnZ3NhdmUoZmlsZW5hbWUgPSBwYXN0ZTAoImJhc2VsaW5lX3RyNDVoaWdoZXhwciBIZWF0bWFwIiwiLnBuZyIpLCBkZXZpY2UgPSBwbmcsIGhlaWdodCA9IDgsIHdpZHRoID0gMTIsIHBsb3QgPSBUcjQ1aGlnaGV4cHIyKQpgYGAKCgojIyBUQwpgYGB7cn0KY3RybF9maWx0ZXJlZCA8LSBGaW5kTmVpZ2hib3JzKGN0cmxfZmlsdGVyZWQpCiMgRGltUGxvdChsYXJ2YSxsYWJlbCA9IFQsIGNlbGxzLmhpZ2hsaWdodCA9IFdoaWNoQ2VsbHMobGFydmFfd3QsaWRlbnQ9ICJEVCIpKSArIHhsaW0oLTE1LDE1KSArIHlsaW0oLTE1LDE1KQoKbGFydmEgPC0gRmluZFN1YkNsdXN0ZXIoY3RybF9maWx0ZXJlZCwgIkFTUCtUQyIsIlNDVF9zbm4iLHJlc29sdXRpb24gPSAwLjMpCnVtYXBwbG90KGxhcnZhLCBncm91cC5ieSA9ICJzdWIuY2x1c3RlciIpCgpUQyA8LSBzdWJzZXQobGFydmEsaWRlbnRzID0gIkFTUCtUQyIpCklkZW50cyhUQykgPC0gVEMkc3ViLmNsdXN0ZXIKdW1hcHBsb3QoVEMsIGdyb3VwLmJ5ID0gInN1Yi5jbHVzdGVyIikgKyBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygtMiw4KSwgYnJlYWtzID0gTlVMTCkgKyAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoLTgsMiksIGJyZWFrcyA9IE5VTEwpCgoj5a2Q576k55qEbWFya2VyClRDc3ViTWFya2VycyA8LSBGaW5kQWxsTWFya2VycyhUQywgbWluLnBjdCA9IDAuMiwgbG9nZmMudGhyZXNob2xkID0gMC41LCBvbmx5LnBvcyA9IEYpClRDXzNtYXJrZXJzIDwtIEZpbmRNYXJrZXJzKFRDLCBpZGVudC4xID0gIkFTUCtUQ18yIiwgb25seS5wb3MgPSBGLCBsb2dmYy50aHJlc2hvbGQgPSAwLjUpCgpkaG0ocm93bmFtZXMoVENzdWJNYXJrZXJzKSxzZXVvYmogPSBUQykgCgoKVENhdmVybWF0IDwtIGdldF9hdmVyZXhwcl9tYXRfY2x1c3RlcihUQykKcmVmZGF0YSA8LSByZWFkLmNzdigiLi9kYXRhX3RhYmxlcy9ERUdzX2Zyb21fc21hcnRTZXEvQVNQX25vcm1hbGl6ZWRfY291bnRzL2FzcF9ub3JtYWxpemVkX2NvdW50cy5jc3YiLHJvdy5uYW1lcyA9IDEpCnJlZmRhdGEgPC0gYXMubWF0cml4KHJvd01lYW5zKHJlZmRhdGEpKSAj5oyJ6KGM5Y+W5bmz5Z2HCnJlZmRhdGEgPC0gYXMubWF0cml4KGFzLm1hdHJpeChyZWZkYXRhW29yZGVyKHJlZmRhdGEsZGVjcmVhc2luZyA9IFQpLF0pWzE6MTAwMCxdKSAjYnVsayBSTkEtc2Vx55qE5YmNMTAwMOS4quacgOmrmOihqOi+vueahOWfuuWboAojIGdlbmVzZXQgPC0gaW50ZXJzZWN0KHJvd25hbWVzKFRDYXZlcm1hdCksIHJvd25hbWVzKHJlZmRhdGEpKQpyZWZkYXRhIDwtIGFzLm1hdHJpeChyZWZkYXRhW2dlbmVzZXQsXSkKCmNvbG5hbWVzKHJlZmRhdGEpIDwtICJyZWYiCgphbGxkYXRhIDwtIGNiaW5kKHJlZmRhdGEsVENhdmVybWF0W2dlbmVzZXQsXSkKbm9ybWFsaXplZCA8LSBzY2FsZShhbGxkYXRhLGNlbnRlciA9IFQsc2NhbGUgPSBUKQpjb3JtYXQgPC0gY29yKG5vcm1hbGl6ZWQsbWV0aG9kID0gInNwZWFybWFuIikKCnBoZWF0bWFwKGNvcm1hdCxjbHVzdGVyX3Jvd3MgPSBULGJyZWFrcyA9IHVuaXF1ZShjKHNlcSgwLDEsIGxlbmd0aD00MDApKSksIGNvbG9yID0gY29sb3JSYW1wUGFsZXR0ZShjKCIjMUU5MEZGIiwgIndoaXRlIiwgIiNmZjIxMjEiKSkoNDAwKSxib3JkZXJfY29sb3IgPSBOQSxjbHVzdGVyX2NvbHMgPSBULG1haW4gPSAiY29yaGVhdG1hcFRDIikKCgpwaGVhdG1hcChUQ2F2ZXJtYXRbUENnZW5lcyxdLCBicmVha3MgPSB1bmlxdWUoYyhzZXEoMCw0LCBsZW5ndGg9NDAwKSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfY29scz1GLCBzY2FsZSA9ICJub25lIixjbHVzdGVyX3Jvd3MgPSBULCBzaG93X3Jvd25hbWVzID0gRiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBjb2xvclJhbXBQYWxldHRlKGMoIndoaXRlIiwgIiNmZjIxMjEiKSkoNDAwKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgYW5nbGVfY29sID0gNDUsIGJvcmRlcl9jb2xvciA9IE5BLCBtYWluID0gIkFTUF9UcmhpZ2hleHByIEhlYXRtYXAiKQpgYGAKCmBgYHtyfQphdmVyX2V4cHJfbWF0IDwtIGdldF9hdmVyZXhwcl9tYXRfY2x1c3RlcihUQykKY29sbmFtZXMoYXZlcl9leHByX21hdCkgPC0gbGV2ZWxzKFRDQGFjdGl2ZS5pZGVudCkKCiPku45hc3AgdnMgdHI0NeaVsOaNrumbhgphbGxfZ2VuZXMgPC0gcmVhZC5jc3YoIi4vREVHc19mcm9tX3NtYXJ0U2VxL1BybyB2cyBBc3AuY3N2IiwgaGVhZGVyID0gVCxyb3cubmFtZXMgPSAxKQphbGxfZ2VuZXNbaXMubmEoYWxsX2dlbmVzKV0gPC0gIDAKQVNQZ2VuZXMgPC0gYWxsX2dlbmVzW2FsbF9nZW5lcyRiYXNlTWVhbj4xMDAgJiBhbGxfZ2VuZXMkcGFkajwwLjAxICYgYWxsX2dlbmVzJGxvZzJGb2xkQ2hhbmdlPCgtMC41KSxdICNBU1AsbG9nMkZvbGRDaGFuZ2U8KC0wLjUpICAgIFRyNDUsbG9nMkZvbGRDaGFuZ2U+MC41IGJhc2VNZWFuPjEwMDAKQVNQZ2VuZXMgPC0gcm93bmFtZXMoQVNQZ2VuZXMpCkFTUGdlbmVzIDwtIGludGVyc2VjdChBU1BnZW5lcyxyb3duYW1lcyhUQ3N1Yk1hcmtlcnMpKQoKVHI0NWhpZ2hleHByIDwtIHBoZWF0bWFwKGF2ZXJfZXhwcl9tYXRbQVNQZ2VuZXMsXSwgY2x1c3Rlcl9jb2xzPUYsIHNjYWxlID0gInJvdyIsY2x1c3Rlcl9yb3dzID0gVCwgc2hvd19yb3duYW1lcyA9IEYsIGNvbG9yID0gY29sb3JSYW1wUGFsZXR0ZShjKCJ3aGl0ZSIsICIjZmYyMTIxIikpKDQwMCksIGFuZ2xlX2NvbCA9IDQ1LCBib3JkZXJfY29sb3IgPSBOQSwgbWFpbiA9ICJBU1BfVHI0NWhpZ2hleHByIEhlYXRtYXAiKQoKYGBgCgoKIyDmr5TovoNTTUFSVHNlceWSjHNjUk5BLXNlcSBtYXJrZXLln7rlm6DnmoTph43lkIjkuKrmlbAKIyMgQVNQCmBgYHtyfQp0b3BuID0gNDAwMApyZWZkYXRhMCA8LSByZWFkLmNzdigiLi9kYXRhX3RhYmxlcy9ERUdzX2Zyb21fc21hcnRTZXEvQVNQX25vcm1hbGl6ZWRfY291bnRzL2FzcF9ub3JtYWxpemVkX2NvdW50cy5jc3YiLCBoZWFkZXIgPSBULHJvdy5uYW1lcyA9IDEpCnJlZmRhdGEwIDwtIGFzLm1hdHJpeChyb3dNZWFucyhyZWZkYXRhMCkpICPmjInooYzlj5blubPlnYcKcmVmZGF0YTAgPC0gYXMubWF0cml4KGFzLm1hdHJpeChyZWZkYXRhMFtvcmRlcihyZWZkYXRhMCxkZWNyZWFzaW5nID0gVCksXSlbMTp0b3BuLF0pIApnZW5lc2V0MCA8LSBpbnRlcnNlY3QoVmFyaWFibGVGZWF0dXJlcyhjdHJsX2ZpbHRlcmVkKSwgcm93bmFtZXMocmVmZGF0YTApKSAKCnJlZmRhdGExIDwtIHJlYWQuY3N2KCIuL2RhdGFfdGFibGVzL0RFR3NfZnJvbV9zbWFydFNlcS9BU1Bfbm9ybWFsaXplZF9jb3VudHMvbm90Y2hkYXRhc2V0X25vcm1hbGl6ZWRfY291bnRzLmNzdiIscm93Lm5hbWVzID0gMSkKcmVmZGF0YTEgPC0gYXMubWF0cml4KHJvd01lYW5zKHJlZmRhdGExKSkgI+aMieihjOWPluW5s+WdhwpyZWZkYXRhMSA8LSBhcy5tYXRyaXgoYXMubWF0cml4KHJlZmRhdGExW29yZGVyKHJlZmRhdGExLGRlY3JlYXNpbmcgPSBUKSxdKVsxOnRvcG4sXSkgCmdlbmVzZXQxIDwtIGludGVyc2VjdChWYXJpYWJsZUZlYXR1cmVzKGN0cmxfZmlsdGVyZWQpLCByb3duYW1lcyhyZWZkYXRhMSkpIAoKcmVmZGF0YTIgPC0gcmVhZC5jc3YoIi4vZGF0YV90YWJsZXMvREVHc19mcm9tX3NtYXJ0U2VxL0FTUF9ub3JtYWxpemVkX2NvdW50cy9BU1BfVFBNLmNzdiIscm93Lm5hbWVzID0gMSkKcmVmZGF0YTIgPC0gYXMubWF0cml4KHJvd01lYW5zKHJlZmRhdGEyKSkgCnJlZmRhdGEyIDwtIGFzLm1hdHJpeChhcy5tYXRyaXgocmVmZGF0YTJbb3JkZXIocmVmZGF0YTIsZGVjcmVhc2luZyA9IFQpLF0pWzE6dG9wbixdKSAKZ2VuZXNldDIgPC0gaW50ZXJzZWN0KFZhcmlhYmxlRmVhdHVyZXMoY3RybF9maWx0ZXJlZCksIHJvd25hbWVzKHJlZmRhdGEyKSkgCgpjbHVzdGVyX2luZm8gPC0gSWRlbnRzKGN0cmxfZmlsdGVyZWQpICU+JSBsZXZlbHMoKQoKIyBjdHJsX21hcmtlcnMgPC0gRmluZEFsbE1hcmtlcnMoY3RybCwgbG9nZmMudGhyZXNob2xkID0gbG9nKDEuMiksIG1pbi5kaWZmLnBjdCA9IDAuMSkKIyBjdHJsX21hcmtlcnMgPC0gY3RybF9tYXJrZXJzICU+JSBncm91cF9ieShjbHVzdGVyKSAlPiUgc2xpY2VfbWF4KG4gPSA0MDAsIG9yZGVyX2J5ID0gYXZnX2xvZ0ZDKQoKCmZ1bmMgPC0gZnVuY3Rpb24oaSwgZmVhdHVyZSl7CiAgbGVuZ3RoKGludGVyc2VjdChjdHJsX21hcmtlcnNbY3RybF9tYXJrZXJzJGNsdXN0ZXIgPT0gaSxdJGdlbmUsIGZlYXR1cmUpKQp9CmludGVyXzEgPC0gbGFwcGx5KGNsdXN0ZXJfaW5mbywgZnVuYywgZ2VuZXNldDApCmludGVyXzIgPC0gbGFwcGx5KGNsdXN0ZXJfaW5mbywgZnVuYywgZ2VuZXNldDEpCmludGVyXzMgPC0gbGFwcGx5KGNsdXN0ZXJfaW5mbywgZnVuYywgZ2VuZXNldDIpCgoKcGxvdF9seSgKICB4ID0gY2x1c3Rlcl9pbmZvLCB5ID0gYXMubnVtZXJpYyhpbnRlcl8xKSwgbmFtZSA9ICdBU1Bfbm9ybWFsaXplZCcsIHR5cGUgPSAnYmFyJykgJT4lCiAgYWRkX3RyYWNlKHkgPSBhcy5udW1lcmljKGludGVyXzIpLCBuYW1lID0gJ25vdGNoY3RybCcpICU+JSAKICBhZGRfdHJhY2UoeSA9IGFzLm51bWVyaWMoaW50ZXJfMyksIG5hbWUgPSAnQVNQX1RQTScpJT4lIGxheW91dCh0aXRsZSA9IHBhc3RlMCgiQVNQdG9wIiwgYXMuY2hhcmFjdGVyKHRvcG4pKSkKCgpgYGAKCiMjIFBDCmBgYHtyfQpyZWZkYXRhMiA8LSByZWFkLmNzdigiLi9kYXRhX3RhYmxlcy9ERUdzX2Zyb21fc21hcnRTZXEvbm9tYWxpemVkX2V4cHJfdHI0VHI1VHI1XzIuY3N2Iixyb3cubmFtZXMgPSAxKQpjbHVzdGVyX2luZm8gPC0gSWRlbnRzKGN0cmxfZmlsdGVyZWQpICU+JSBsZXZlbHMoKQojIHJlZmRhdGEyIDwtIHJlYWQuY3N2KCJ+L3NpbmdsZSBjZWxsLWF0bGFzIG9mIGZseSB0cmFjaGVhL0FTUF9idWxrUk5Bc2VxL1RyNDVfbm9ybWFsaXplZF9jb3VudHMuY3N2Iixyb3cubmFtZXMgPSAxKQpyZWZkYXRhMiA8LSBhcy5tYXRyaXgocm93TWVhbnMocmVmZGF0YTIpKSAKcmVmZGF0YTIgPC0gYXMubWF0cml4KGFzLm1hdHJpeChyZWZkYXRhMltvcmRlcihyZWZkYXRhMixkZWNyZWFzaW5nID0gVCksXSlbMTo4MDAsXSkgCmdlbmVzZXQyIDwtIGludGVyc2VjdChWYXJpYWJsZUZlYXR1cmVzKGN0cmxfZmlsdGVyZWQpLCByb3duYW1lcyhyZWZkYXRhMikpIAppbnRlciA8LSBsYXBwbHkoY2x1c3Rlcl9pbmZvLCBmdW5jLCBnZW5lc2V0MikKCnBsb3RfbHkoCiAgeCA9IGNsdXN0ZXJfaW5mbywKICB5ID0gYXMubnVtZXJpYyhpbnRlciksCiAgbmFtZSA9ICJhc3B0cmRhdGFzZXQiLCB0eXBlID0gImJhciIpICU+JSBsYXlvdXQodGl0bGUgPSAiUEN0b3A4MDAiKQoKcGhlYXRtYXAoYXZlcl9leHByX21hdFtnZW5lc2V0MixdLCBjbHVzdGVyX2NvbHM9Riwgc2NhbGUgPSAibm9uZSIsY2x1c3Rlcl9yb3dzID0gVCwgc2hvd19yb3duYW1lcyA9IEYsIGNvbG9yID0gY29sb3JSYW1wUGFsZXR0ZShjKCAid2hpdGUiLCAiI2ZmMjEyMSIpKSg0MDApLCBhbmdsZV9jb2wgPSA0NSwgYm9yZGVyX2NvbG9yID0gTkEsIG1haW4gPSAiUEN0b3A4MDAgSGVhdG1hcCIpCgpgYGAKYGBge3J9CmxpYnJhcnkoVXBTZXRSKQpmdW5jMjIgPC0gZnVuY3Rpb24oaSwgZmVhdHVyZSl7CiAgaW50ZXJzZWN0KGN0cmxfbWFya2Vyc1tjdHJsX21hcmtlcnMkY2x1c3RlciA9PSBpLF0kZ2VuZSwgZmVhdHVyZSkKfQoKZGF0YSA9ICBsYXBwbHkoY2x1c3Rlcl9pbmZvLCBmdW5jMjIsIGdlbmVzZXQyKQpuYW1lcyhkYXRhKSA8LSBjbHVzdGVyX2luZm8KdXBzZXQoZnJvbUxpc3QoZGF0YSksbnNldHMgPSBsZW5ndGgoZGF0YSksIHNldHMgPSBjbHVzdGVyX2luZm8pCmBgYA==